<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>碎片化轮播图</title>
    <style>
      /*css样式*/
      /* 自定义颜色变量 */
      :root {
        --primary: #4c6ef5;
        --secondary: #339af0;
        --dark: #1a1a2e;
        --light: #f8f9fa;
        --image-width: 60%;
        --image-height: 60%;
        --transition-duration: 0.8s;
      }

      /* 基础样式 */
      body {
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        margin: 0;
        overflow: hidden;
      }

      .container {
        width: var(--image-width);
        height: var(--image-height);
      }

      /* 轮播图容器 */
      .carousel-container {
        position: relative;
        border-radius: 0.75rem;
        overflow: hidden;
        box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.3);
      }

      /* 轮播图片区域 */
      .carousel {
        position: relative;
        width: 100%;
        aspect-ratio: 16/9;
      }

      /* 轮播图 */
      .slide {
        position: absolute;
        inset: 0;
        opacity: 0;
        transition: opacity 300ms;
      }

      .slide.active {
        opacity: 1;
      }

      .slide img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }

      /* 导航按钮 */
      .nav-btn {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: 3rem;
        height: 3rem;
        display: flex;
        align-items: center;
        justify-content: center;
        background: rgba(255, 255, 255, 0.2);
        backdrop-filter: blur(4px);
        border-radius: 50%;
        color: white;
        transition: all 300ms;
        cursor: pointer;
        border: none;
        outline: none;
        z-index: 10;
        font-size: 2rem;
      }

      .nav-btn:hover {
        background: rgba(76, 110, 245, 0.8);
        transform: translateY(-50%) scale(1.1);
      }

      .nav-btn.prev {
        left: 1rem;
      }

      .nav-btn.next {
        right: 1rem;
      }

      /* 指示器 */
      .indicators {
        position: absolute;
        bottom: 1rem;
        left: 50%;
        transform: translateX(-50%);
        display: flex;
        gap: 0.5rem;
        z-index: 10;
      }

      .dot {
        width: 0.75rem;
        height: 0.75rem;
        border-radius: 50%;
        background: rgba(255, 255, 255, 0.8);
        transition: all 300ms;
        cursor: pointer;
        border: none;
        outline: none;
      }

      .dot.active {
        width: 2rem;
        border-radius: 0.375rem;
        background: #4c6ef5;
      }

      /* 碎片 */
      .fragment {
        position: absolute;
        pointer-events: none;
        transition: all var(--transition-duration)
          cubic-bezier(0.2, 0.8, 0.2, 1);
      }
    </style>
  </head>
  <body>
    <div class="container">
      <!-- 轮播图容器 -->
      <div class="carousel-container" id="carousel-container">
        <!-- 轮播图片区域 -->
        <div class="carousel" id="carousel">
          <!-- 轮播图片将通过JS动态添加 -->
        </div>

        <!-- 导航按钮 -->
        <button class="nav-btn prev" id="prev-btn">
          <span>‹</span>
        </button>
        <button class="nav-btn next" id="next-btn">
          <span>›</span>
        </button>

        <!-- 指示器 -->
        <div class="indicators" id="indicators">
          <!-- 指示器点将通过JS动态添加 -->
        </div>
      </div>
    </div>

    <script>
      //js逻辑
      // 轮播图配置
      const carouselConfig = {
        images: [
          {
            src: "http://5b0988e595225.cdn.sohucs.com/images/20180130/24aecf0d680546ccbf6480badce389dc.jpeg",
            alt: "千与千寻",
          },
          {
            src: "https://pic3.zhimg.com/v2-f1159536dc58af663e3955e774a7a13a_r.jpg",
            alt: "龙猫",
          },
          {
            src: "http://qqpublic.qpic.cn/qq_public_cover/0/0-2083471255-1DB77954D274653D98B57D000A686040_vsmcut/0",
            alt: "天空之城",
          },
          {
            src: "https://nimg.ws.126.net/?url=http%3A%2F%2Fdingyue.ws.126.net%2F2022%2F1101%2F9be4344ej00rkno8n00y7d200u000g6g00zk00j5.jpg",
            alt: "借东西的小人阿莉埃蒂",
          },
          {
            src: "http://5b0988e595225.cdn.sohucs.com/images/20180824/781646fe72fc4788b7dfc24c112b5bbb.png",
            alt: "悬崖上的金鱼姬",
          },
          {
            src: "http://p6.itc.cn/q_70/images03/20210106/6cd651a28f9a46268205410dcc5cad4d.jpeg",
            alt: "魔女宅急便",
          },
          {
            src: "https://wenhui.whb.cn/u/cms/www/201907/04234229c951.jpg",
            alt: "幽灵公主",
          },
        ],
        fragmentConfig: {
          rows: 10, // 碎片行数
          cols: 15, // 碎片列数
          maxDisplacement: 400, // 碎片最大位移距离
          maxRotation: 180, // 碎片最大旋转角度
          minScale: 0.3, // 碎片最小缩放比例
        },
        autoplay: true, // 是否自动播放
        autoplaySpeed: 5000, // 自动播放速度(毫秒)
        transitionDuration: 800, // 过渡动画持续时间(毫秒)
      };

      // DOM元素
      const carouselContainer = document.getElementById("carousel");
      const prevBtn = document.getElementById("prev-btn");
      const nextBtn = document.getElementById("next-btn");
      const indicators = document.getElementById("indicators");

      // 状态变量
      let currentSlide = 0;
      let autoplayInterval;
      let isPlaying = carouselConfig.autoplay;
      let autoplaySpeed = carouselConfig.autoplaySpeed;
      let isTransitioning = false; // 过渡状态锁
      //使用transitionDuration更新css变量
      const transitionDuration = carouselConfig.transitionDuration;
      document.documentElement.style.setProperty(
        "--transition-duration",
        `${transitionDuration / 1000}s`
      );

      // 初始化轮播图
      function initCarousel() {
        // 创建轮播图片
        carouselConfig.images.forEach((image, index) => {
          const slide = document.createElement("div");
          slide.className = `slide ${index === 0 ? "active" : ""}`;
          slide.dataset.index = index;

          const img = document.createElement("img");
          img.src = image.src;
          img.alt = image.alt;

          slide.appendChild(img);
          carouselContainer.appendChild(slide);

          // 创建指示器
          const dot = document.createElement("button");
          dot.className = `dot ${index === 0 ? "active" : ""}`;
          dot.dataset.index = index;
          dot.addEventListener("click", () => goToSlide(index));
          indicators.appendChild(dot);
        });

        // 设置自动播放
        if (isPlaying) {
          startAutoplay();
        }

        // 绑定事件
        prevBtn.addEventListener("click", () => {
          if (!isTransitioning) goToPrevSlide();
        });
        nextBtn.addEventListener("click", () => {
          if (!isTransitioning) goToNextSlide();
        });
      }

      // 切换到指定轮播图
      function goToSlide(index) {
        if (index === currentSlide || isTransitioning) return;

        isTransitioning = true; // 锁定过渡状态

        const slides = document.querySelectorAll(".slide");
        const currentSlideEl = slides[currentSlide];
        const newSlideEl = slides[index];

        // 碎片化当前轮播图
        fragmentImage(currentSlideEl.querySelector("img"), () => {
          // 隐藏当前轮播图，显示新轮播图
          currentSlideEl.classList.remove("active");
          newSlideEl.classList.add("active");
          currentSlide = index;

          // 重置自动播放计时器
          if (isPlaying) {
            resetAutoplay();
          }

          // 解除锁定
          isTransitioning = false;
        });
        currentSlideEl.style.opacity = "0";
        newSlideEl.style.opacity = "1";
        currentSlide = index;
        // 更新指示器
        document.querySelectorAll(".dot").forEach((dot, i) => {
          dot.classList.toggle("active", i === index);
        });
      }

      // 切换到上一张
      function goToPrevSlide() {
        const newIndex =
          (currentSlide - 1 + carouselConfig.images.length) %
          carouselConfig.images.length;
        goToSlide(newIndex);
      }

      // 切换到下一张
      function goToNextSlide() {
        const newIndex = (currentSlide + 1) % carouselConfig.images.length;
        goToSlide(newIndex);
      }

      // 图片碎片化函数
      function fragmentImage(img, callback) {
        if (!img.complete) {
          if (callback) callback();
          return;
        }

        // 移除之前的碎片
        const existingFragments =
          carouselContainer.querySelectorAll(".fragment");
        existingFragments.forEach((frag) => frag.remove());

        // 获取图片尺寸和容器尺寸
        const imgWidth = img.naturalWidth;
        const imgHeight = img.naturalHeight;
        const containerWidth = carouselContainer.offsetWidth;
        const containerHeight = carouselContainer.offsetHeight;

        // 计算容器和图片的宽高比
        const containerRatio = containerWidth / containerHeight;
        const imgRatio = imgWidth / imgHeight;

        // 计算实际显示的图片尺寸（考虑object-cover的影响）
        let displayWidth, displayHeight;
        if (imgRatio > containerRatio) {
          // 图片比容器宽，高度填满容器，宽度超出
          displayHeight = containerHeight;
          displayWidth = displayHeight * imgRatio;
        } else {
          // 图片比容器高，宽度填满容器，高度超出
          displayWidth = containerWidth;
          displayHeight = displayWidth / imgRatio;
        }

        // 计算图片在容器中的偏移（居中显示）
        const offsetX = (displayWidth - containerWidth) / 2;
        const offsetY = (displayHeight - containerHeight) / 2;

        // 设置碎片参数
        const { rows, cols, maxDisplacement, maxRotation, minScale } =
          carouselConfig.fragmentConfig;
        const fragmentWidth = displayWidth / cols;
        const fragmentHeight = displayHeight / rows;

        // 创建碎片
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < cols; j++) {
            const fragment = document.createElement("div");
            fragment.className = "fragment";

            // 设置碎片的位置和大小
            fragment.style.left = `${j * fragmentWidth - offsetX}px`;
            fragment.style.top = `${i * fragmentHeight - offsetY}px`;
            fragment.style.width = `${fragmentWidth}px`;
            fragment.style.height = `${fragmentHeight}px`;

            // 使用背景图定位来显示原图的相应部分
            fragment.style.backgroundImage = `url(${img.src})`;
            fragment.style.backgroundSize = `${displayWidth}px ${displayHeight}px`;
            fragment.style.backgroundPosition = `-${j * fragmentWidth}px -${
              i * fragmentHeight
            }px`;

            // 设置初始样式
            fragment.style.opacity = "1";
            fragment.style.transform = "translate(0, 0) rotate(0) scale(1)";

            // 添加到容器
            carouselContainer.appendChild(fragment);

            // 延迟触发动画
            setTimeout(() => {
              // 计算随机位移、旋转和不透明度
              const randomX = (Math.random() - 0.5) * maxDisplacement;
              const randomY = (Math.random() - 0.5) * maxDisplacement;
              const randomRotation = (Math.random() - 0.5) * maxRotation;
              const randomScale = minScale + Math.random() * (1 - minScale);

              fragment.style.transform = `translate(${randomX}px, ${randomY}px) rotate(${randomRotation}deg) scale(${randomScale})`;
              fragment.style.opacity = "0";
            }, (i * cols + j) * 10);
          }
        }

        // 动画结束后移除碎片并执行回调
        const totalDuration =
          carouselConfig.transitionDuration + rows * cols * 10;
        setTimeout(() => {
          const fragments = carouselContainer.querySelectorAll(".fragment");
          fragments.forEach((frag) => frag.remove());
          if (callback) callback();
        }, totalDuration);
      }

      // 开始自动播放
      function startAutoplay() {
        autoplayInterval = setInterval(() => {
          if (!isTransitioning) goToNextSlide();
        }, autoplaySpeed);
      }

      // 停止自动播放
      function stopAutoplay() {
        clearInterval(autoplayInterval);
      }

      // 重置自动播放计时器
      function resetAutoplay() {
        if (isPlaying) {
          clearInterval(autoplayInterval);
          startAutoplay();
        }
      }

      // 响应式处理
      function handleResize() {
        // 可添加调整碎片大小的逻辑
      }

      // 初始化
      initCarousel();
      window.addEventListener("resize", handleResize);
    </script>
  </body>
</html>
